package com.ruoyi.lxgl.kylx.controller;

import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.entity.SysDept;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.utils.DictUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.WordUtil;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.infoRunTaskData.domain.InfoRunTaskData;
import com.ruoyi.infoRunTaskData.service.IInfoRunTaskDataService;
import com.ruoyi.lxgl.kylx.domain.*;
import com.ruoyi.lxgl.kylx.mapper.LlglXmsbMapper;
import com.ruoyi.lxgl.kylx.service.ILlglXmsbService;
import com.ruoyi.system.mapper.SysDeptMapper;
import com.ruoyi.system.service.ISysDeptService;
import com.spire.doc.*;
import com.spire.doc.documents.Paragraph;
import com.spire.doc.documents.ParagraphStyle;
import com.spire.doc.fields.DocPicture;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.poi.xwpf.usermodel.XWPFRun;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.IntStream;

/**
 * 项目申报Controller
 *
 * @author huacai
 * @date 2024-03-14
 */
@RestController
@RequestMapping("/kylx/xmsb")
@Api(tags = "项目申报")
public class LlglXmsbController extends BaseController {

    @Value(value = "${ruoyi.profile}")
    private String profile;

    @Value(value = "${server.port}")
    private String portNum;

    private final String temporaryFilePath = "/temporary/";


    private final String hostAddress = "https://s10.s100.vip:22308";

    @Resource
    private ILlglXmsbService llglXmsbService;

    @Resource
    private LlglXmsbMapper llglXmsbMapper;

    @Resource
    private ISysDeptService deptService;

    @Resource
    private IInfoRunTaskDataService iInfoRunTaskDataService;


    /**
     * 查询项目申报列表
     */
    @PreAuthorize("@ss.hasPermi('kylx:xmsb:list')")
    @GetMapping("/list")
    @ApiOperation("查询项目申报列表")
    public TableDataInfo list(LlglXmsb llglXmsb) {
        startPage();
        List<LlglXmsb> list = llglXmsbService.selectLlglXmsbList(llglXmsb);
//        for (LlglXmsb item : list) {
//            item.setZrBm(deptService.selectDeptById(Long.valueOf(item.getZrBm())).getDeptName());
//        }
        return getDataTable(list);
    }

    /**
     * 查询项目申报列表 (项目申报使用)
     * @param llglXmsb
     * @return
     */
    @PreAuthorize("@ss.hasPermi('kylx:xmsb:list')")
    @GetMapping("/getXmsbList")
    @ApiOperation("查询项目申报列表(项目申报页面使用)")
    public TableDataInfo getXmsbList(LlglXmsb llglXmsb) {
        startPage();
        List<LlglXmsb> list = llglXmsbService.getXmsbList(llglXmsb);
//        for (LlglXmsb item : list) {
//            item.setZrBm(deptService.selectDeptById(Long.valueOf(item.getZrBm())).getDeptName());
//        }
        return getDataTable(list);
    }

    /**
     * 导出项目申报列表
     */
    @PreAuthorize("@ss.hasPermi('kylx:xmsb:export')")
    @Log(title = "项目申报", businessType = BusinessType.EXPORT)
    @PostMapping("/export")
    @ApiOperation("导出项目申报列表")
    public void export(HttpServletResponse response, LlglXmsb llglXmsb) {
        List<LlglXmsb> list = llglXmsbService.selectLlglXmsbList(llglXmsb);
        ExcelUtil<LlglXmsb> util = new ExcelUtil<LlglXmsb>(LlglXmsb.class);
        util.exportExcel(response, list, "项目申报数据");
    }

    /**
     * 下载模板
     */
    @PostMapping("/importTemplate")
    public void importTemplate(HttpServletResponse response) {
        ExcelUtil<LlglXmsb> util = new ExcelUtil<LlglXmsb>(LlglXmsb.class);
        util.importTemplateExcel(response, "项目申报数据");
    }

    /**
     * 导入数据
     */
    @Log(title = "项目申报", businessType = BusinessType.IMPORT)
    @PreAuthorize("@ss.hasPermi('kylx:xmsb:import')")
    @PostMapping("/importData")
    public AjaxResult importData(MultipartFile file) throws Exception {
        ExcelUtil<LlglXmsb> util = new ExcelUtil<LlglXmsb>(LlglXmsb.class);
        InputStream inputStream = file.getInputStream();
        List<LlglXmsb> list = util.importExcel(inputStream);
        inputStream.close();
        int count = llglXmsbService.batchInsertLlglXmsb(list);
        return AjaxResult.success("导入成功" + count + "条信息！");
    }

    /**
     * 获取项目申报详细信息
     */
    @PreAuthorize("@ss.hasPermi('kylx:xmsb:query')")
    @GetMapping(value = "/{xmsbId}")
    public AjaxResult getInfo(@PathVariable("xmsbId") Integer xmsbId) {
        return success(llglXmsbService.selectLlglXmsbByXmsbId(xmsbId));
    }

    /**
     * 获取项目申报与项目计划进度和目标详细信息
     */
    @PreAuthorize("@ss.hasPermi('kylx:xmsb:query')")
    @GetMapping(value = "/jhjd/{xmsbId}")
    public AjaxResult selectLlglXmsbByjhjdByXmsbId(@PathVariable("xmsbId") Integer xmsbId) {
        return success(llglXmsbService.selectLlglXmsbByjhjdByXmsbId(xmsbId));
    }

    /**
     * 获取项目申报与研发费用预算上信息信息
     */
    @PreAuthorize("@ss.hasPermi('kylx:xmsb:query')")
    @GetMapping(value = "/yffy/{xmsbId}")
    public AjaxResult selectLlglXmsbByyffyByXmsbId(@PathVariable("xmsbId") Integer xmsbId) {
        return success(llglXmsbService.selectLlglXmsbByyffyByXmsbId(xmsbId));
    }

    /**
     * 获取项目申报与研发费用预算下信息信息
     */
    @PreAuthorize("@ss.hasPermi('kylx:xmsb:query')")
    @GetMapping(value = "/yffys/{xmsbId}")
    public AjaxResult selectLlglXmsbByyffysByXmsbId(@PathVariable("xmsbId") Integer xmsbId) {
        return success(llglXmsbService.selectLlglXmsbByyffysByXmsbId(xmsbId));
    }

    /**
     * 获取项目申报与研发费用研发材料
     */
    @PreAuthorize("@ss.hasPermi('kylx:xmsb:query')")
    @GetMapping(value = "/yfcl/{xmsbId}")
    public AjaxResult selectLlglXmsbByYfclByXmsbId(@PathVariable("xmsbId") Integer xmsbId) {
        return success(llglXmsbService.selectLlglXmsbByYfclByXmsbId(xmsbId));
    }

    /**
     * 获取项目申报与研发费用研发材料
     */
    @PreAuthorize("@ss.hasPermi('kylx:xmsb:query')")
    @GetMapping(value = "/yfsb/{xmsbId}")
    public AjaxResult selectLlglXmsbYfsbByXmsbId(@PathVariable("xmsbId") Integer xmsbId) {
        return success(llglXmsbService.selectLlglXmsbYfsbByXmsbId(xmsbId));
    }

    /**
     * 获取项目申报与研发费用中间试验费
     */
    @PreAuthorize("@ss.hasPermi('kylx:xmsb:query')")
    @GetMapping(value = "/zjsyf/{xmsbId}")
    public AjaxResult selectLlglXmsbZjsyfByXmsbId(@PathVariable("xmsbId") Integer xmsbId) {
        return success(llglXmsbService.selectLlglXmsbZjsyfByXmsbId(xmsbId));
    }

    /**
     * 获取项目申报与课题组成人员
     */
    @PreAuthorize("@ss.hasPermi('kylx:xmsb:query')")
    @GetMapping(value = "/zcry/{xmsbId}")
    public AjaxResult selectLlglXmsbZcryByXmsbId(@PathVariable("xmsbId") Integer xmsbId) {
        return success(llglXmsbService.selectLlglXmsbZcryByXmsbId(xmsbId));
    }

    /**
     * 新增项目申报
     */
    @PreAuthorize("@ss.hasPermi('kylx:xmsb:add')")
    @Log(title = "项目申报", businessType = BusinessType.INSERT)
    @PostMapping
    public AjaxResult add(@RequestBody LlglXmsb llglXmsb) {
        llglXmsb.setUserId(Math.toIntExact(getUserId()));
        int insertLlGlXmsb = llglXmsbService.insertLlglXmsb(llglXmsb);
        //向流程业务表中加入数据
        InfoRunTaskData infoRunTaskData = new InfoRunTaskData();
        infoRunTaskData.setBusinessKey(String.valueOf(llglXmsb.getXmsbId()));
        infoRunTaskData.setBusinessType(2);
        infoRunTaskData.setBusinessTitle(llglXmsb.getKtName());
        infoRunTaskData.setApplyUser(SecurityUtils.getLoginUser().getUser().getNickName());//申请人

        iInfoRunTaskDataService.insertInfoRunTaskData(infoRunTaskData);

        return success(llglXmsb.getXmsbId());
    }

    /**
     * 修改项目申报
     */
    @PreAuthorize("@ss.hasPermi('kylx:xmsb:edit')")
    @Log(title = "项目申报", businessType = BusinessType.UPDATE)
    @PutMapping
    public AjaxResult edit(@RequestBody LlglXmsb llglXmsb) {
//        Map<String, Integer> jhjdMaxAndMinNum = llglXmsbService.getJhjdMaxAndMinNum(llglXmsb.getXmsbId());
//        Integer minOrderNunm = 1000;
//        if (jhjdMaxAndMinNum == null) {
//        } else {
//            minOrderNunm = jhjdMaxAndMinNum.get("minOrderNunm");
//        }

        //修改业务中间表关系数据
        InfoRunTaskData infoRunTaskData = new InfoRunTaskData();
        infoRunTaskData.setBusinessTitle(llglXmsb.getKtName());
        infoRunTaskData.setBusinessKey(String.valueOf(llglXmsb.getXmsbId()));
        infoRunTaskData.setBusinessType(2);
        iInfoRunTaskDataService.updateInfoRunTaskData(infoRunTaskData);

        return toAjax(llglXmsbService.updateLlglXmsb(llglXmsb));
    }


    /**
     * 课题归属转换
     */
    @PutMapping("/updateKtgs")
    public AjaxResult updateKtgs(@RequestBody LlglXmsb llglXmsb) {
        return toAjax(llglXmsbService.updateKtgs(llglXmsb));
    }

    /**
     * 删除项目申报
     */
    @PreAuthorize("@ss.hasPermi('kylx:xmsb:remove')")
    @Log(title = "项目申报", businessType = BusinessType.DELETE)
    @DeleteMapping("/{xmsbIds}")
    public AjaxResult remove(@PathVariable Integer[] xmsbIds) {
        //同时删除业务关系数据
        for (Integer id : xmsbIds) {
            LlglXmsb llglXmsb = llglXmsbService.selectLlglXmsbByXmsbId(id);
            iInfoRunTaskDataService.deleteData(String.valueOf(llglXmsb.getXmsbId()), 2);
        }
        return toAjax(llglXmsbService.deleteLlglXmsbByXmsbIds(xmsbIds));
    }

    /**
     * 查询当前公司今年已立项的立项数
     *
     * @param year       xxxx-xx-xxx中的xx
     * @param middlePart xxxx-xx-xxx中的xxxx
     * @return 当前xx的xxx
     */
    @GetMapping("/count")
    @ApiOperation("查询当前公司今年已立项的立项数")
    public int selectProjectNumber(@RequestParam String year, @RequestParam String middlePart) {
        return llglXmsbMapper.selectProjectNumber(year, middlePart);
    }

    /**
     * 查询当前公司今年已立项的最新的立项编号
     */
    @GetMapping("/countLxbh")
    public String selectCountLxbh(@RequestParam String year, @RequestParam String middlePart) {
        return llglXmsbMapper.selectCountLxbh(year, middlePart);
    }


    /**
     * 新增附件
     */
    @PostMapping("/add/File/By/subId")
    public AjaxResult insertLxglXmsbFjByxmsbId(@RequestBody LxglXmsbFj lxglXmsbFj) {
        return toAjax(llglXmsbService.insertLxglXmsbFjByxmsbId(lxglXmsbFj));
    }

    /**
     * 根据主表ID查询附件列表
     */
    @GetMapping("/get/FileList/By/subId")
    public AjaxResult selectLxglXmsbFjList(Integer sId) {
        LxglXmsbFj lxglXmsbFj = new LxglXmsbFj();
        lxglXmsbFj.setXmsbId(sId);
        return AjaxResult.success(llglXmsbService.selectLxglXmsbFjList(lxglXmsbFj));
    }

    /**
     * 根据id删除附件
     */
    @GetMapping("/remove/file/by/id")
    public AjaxResult removeFileBySunId(Integer id) {
        return AjaxResult.success(llglXmsbService.deleteLxglXmsbFjByFjId(id));
    }

    /**
     * 查询当前最新的主表主键ID
     */
    @ApiOperation("查询当前最新的主表主键ID")
    @GetMapping("/selectMAXId")
    public AjaxResult selectMAXId() {
        return AjaxResult.success(llglXmsbService.selectMAXId());
    }

    /**
     * 移动计划进度行数据顺序
     */
    @ApiOperation("移动计划进度行数据顺序")
    @PostMapping("/move/jhjd/row")
    public AjaxResult moveJhjdRowData(@RequestBody LxglXmsbJhjd jhjd) {
        Map<String, Integer> jhjdMaxAndMinNum = llglXmsbService.getJhjdMaxAndMinNum(jhjd.getXmsbId());
        if (jhjd.getMoveType() == 1) {
            // 上移动
            Integer maxOrderNum = jhjdMaxAndMinNum.get("maxOrderNum");
            if (jhjd.getOrderNum() == maxOrderNum) {
                return AjaxResult.error("已处于第一行!");
            }
            List<LxglXmsbJhjd> jhjdList = llglXmsbService.getJhjdList(jhjd.getXmsbId());
            Integer downNum = 0;
            Integer upNum = 0;
            for (int i = 0; i < jhjdList.size(); i++) {
                // 当前
                if (jhjd.getJhjdId() == jhjdList.get(i).getJhjdId()) {
                    // 即将要变的高顺序号
                    upNum = jhjdList.get(i - 1).getOrderNum();
                    downNum = jhjdList.get(i).getOrderNum();

                    LxglXmsbJhjd lxglXmsbJhjd = jhjdList.get(i - 1);
                    lxglXmsbJhjd.setOrderNum(downNum);
                    llglXmsbService.updateLxglXmsbJhjd(lxglXmsbJhjd);
                    LxglXmsbJhjd lxglXmsbJhjd1 = jhjdList.get(i);
                    lxglXmsbJhjd1.setOrderNum(upNum);
                    llglXmsbService.updateLxglXmsbJhjd(lxglXmsbJhjd1);
                    break;
                }
            }
        } else {
            //下移
            Integer minOrderNunm = jhjdMaxAndMinNum.get("minOrderNunm");
            if (jhjd.getOrderNum() == minOrderNunm) {
                return AjaxResult.error("已处于最后一行!");
            }
            List<LxglXmsbJhjd> jhjdList = llglXmsbService.getJhjdList(jhjd.getXmsbId());
            Integer downNum = 0;
            Integer upNum = 0;

            for (int i = 0; i < jhjdList.size(); i++) {
                if (jhjd.getJhjdId() == jhjdList.get(i).getJhjdId()) {
                    upNum = jhjdList.get(i + 1).getOrderNum();
                    downNum = jhjdList.get(i).getOrderNum();

                    // 下一行数据  小num
                    LxglXmsbJhjd lxglXmsbJhjd = jhjdList.get(i + 1);
                    // 小num变大
                    lxglXmsbJhjd.setOrderNum(downNum);
                    llglXmsbService.updateLxglXmsbJhjd(lxglXmsbJhjd);

                    LxglXmsbJhjd lxglXmsbJhjd1 = jhjdList.get(i);
                    // 大num变小
                    lxglXmsbJhjd1.setOrderNum(upNum);
                    llglXmsbService.updateLxglXmsbJhjd(lxglXmsbJhjd1);
                    break;
                }
            }
        }
        return AjaxResult.success();
    }

    @Resource
    private SysDeptMapper deptMapper;

    /**
     * 根据模板导出word
     *
     * @param xmsbId   项目申报ID
     * @param request  HttpServlet请求对象
     * @param response 扩展Servlet响应接口，以便在发送响应时提供特定于HTTP的功能。
     * @return docx
     */
    @Log(title = "根据模板导出word", businessType = BusinessType.EXPORT)
//    @PreAuthorize("@ss.hasPermi('occupation:basics:exportWord')")
    @GetMapping("/exportWord/{xmsbId}")
    public AjaxResult exportXmsbWord(@PathVariable("xmsbId") Integer xmsbId, HttpServletRequest request, HttpServletResponse response) {
        LlglXmsb llglXmsb = llglXmsbService.selectLlglXmsbByXmsbId(xmsbId);

        String ktName = llglXmsb.getKtName(); //课题名称
        String ktBh = llglXmsb.getKtBh(); //课题编号

//        String zrBmId = llglXmsb.getZrBm(); //获取所填入部门的部门ID
//        SysDept zrbmList = deptMapper.selectDeptById(Long.valueOf(zrBmId)); //根据部门ID查询该部门信息
//        String zrBm = zrbmList.getDeptName(); //承担单位(根据该部门的全部信息获取部门名称)
        String zrBm = llglXmsb.getZrBm(); //获取所填入部门的部门

        // 创建一个 SimpleDateFormat 对象，指定日期格式
        SimpleDateFormat sdfYM = new SimpleDateFormat("yyyy-MM");
        Date getqTime = llglXmsb.getQTime(); //获取起时间
        String qTime = sdfYM.format(getqTime); // 使用 SimpleDateFormat 对象将 Date 对象格式化为 String 对象
        Date getzTime = llglXmsb.getZTime(); //获取止时间
        String zTime = sdfYM.format(getzTime); // 使用 SimpleDateFormat 对象将 Date 对象格式化为 String 对象

        String fzName = llglXmsb.getFzName(); //项目负责人
        String txdz = llglXmsb.getTxdz(); //通信地址
        String fzYzbm = llglXmsb.getFzYzbm(); //邮政编码
        String fzPhone = llglXmsb.getFzPhone(); //联系电话

        // 创建一个 SimpleDateFormat 对象，指定日期格式
        SimpleDateFormat sdfYMD = new SimpleDateFormat("yyyy-MM-dd");
        Date getSbRq = llglXmsb.getSbRq(); //获取申请日期
        String sbRq = sdfYMD.format(getSbRq); // 使用 SimpleDateFormat 对象将 Date 对象格式化为 String 对象

        String fzXbDict = llglXmsb.getFzXb(); //负责人性别 字典的键值
        String fzXb = DictUtils.getDictLabel("sys_user_sex", fzXbDict); //负责人性别

        Integer fzNl = llglXmsb.getFzNl(); //负责人年龄
        String fzZy = llglXmsb.getFzZy(); //负责人专业
        String fzZcDict = llglXmsb.getFzZc(); //负责人职称 字典键值
        String fzZc = DictUtils.getDictLabel("rcpt_zc", fzZcDict); //负责人性别
        String ktFl = llglXmsb.getKtFl(); // 可能是 "3,2,1" 或 "1" 或其他组合

        //课题分类各项
        String jsGg = "□";      //0 技术攻关
        String xjsKf = "□";     //1 新技术开发
        String xcpSz = "□";     //2 新产品试制
        String jsYjXhXs = "□";  //3 技术引进消化吸收
        String yyLlJcYj = "□";  //4 应用理论基础研究
        String rkxYj = "□";     //5 软科学研究
        String tg = "□";        //6 推广

        String sqDwYj = llglXmsb.getSqDwYj(); //申请单位意见
        String csYj = llglXmsb.getCsYj(); //技术中心意见(初审意见)

        // 检查字符串是否包含逗号
        if (ktFl.contains(",")) {
            // 使用逗号分隔字符串并存储到数组中
            String[] numbers = ktFl.split(",");
            // 检查数组中是否包含各个数字
            if (Arrays.asList(numbers).contains("0")) {
                jsGg = "■";
            }
            if (Arrays.asList(numbers).contains("1")) {
                xjsKf = "■";
            }
            if (Arrays.asList(numbers).contains("2")) {
                xcpSz = "■";
            }
            if (Arrays.asList(numbers).contains("3")) {
                jsYjXhXs = "■";
            }
            if (Arrays.asList(numbers).contains("4")) {
                yyLlJcYj = "■";
            }
            if (Arrays.asList(numbers).contains("5")) {
                rkxYj = "■";
            }
            if (Arrays.asList(numbers).contains("6")) {
                tg = "■";
            }
        } else {
            // 直接检查字符串是否等于各个数字
            if (ktFl.equals("0")) {
                jsGg = "■";
            }
            if (ktFl.equals("1")) {
                xjsKf = "■";
            }
            if (ktFl.equals("2")) {
                xcpSz = "■";
            }
            if (ktFl.equals("3")) {
                jsYjXhXs = "■";
            }
            if (ktFl.equals("4")) {
                yyLlJcYj = "■";
            }
            if (ktFl.equals("5")) {
                rkxYj = "■";
            }
            if (ktFl.equals("6")) {
                tg = "■";
            }
        }


        Map<String, Object> map = new HashMap<>();

        map.put("ktBh", ktBh); //课题编号
        map.put("ktName", ktName); //课题名称
        map.put("zrBm", zrBm); //承担单位
        map.put("qTime", qTime); //起时间
        map.put("zTime", zTime); //止时间
        map.put("fzName", fzName); //项目负责人
        map.put("txdz", txdz); //通信地址
        map.put("fzYzbm", fzYzbm); //邮政编码
        map.put("fzPhone", fzPhone); //联系电话
        map.put("sbRq", sbRq); //申请日期
        map.put("fzXb", fzXb); //负责人性别
        map.put("fzNl", fzNl); //负责人年龄
        map.put("fzZy", fzZy); //负责人专业
        map.put("fzZc", fzZc); //负责人职称

        //课题分类各选项
        map.put("jsGg", jsGg); //技术攻关
        map.put("xjsKf", xjsKf); //技术攻关
        map.put("xcpSz", xcpSz); //新产品试制
        map.put("jsYjXhXs", jsYjXhXs); //技术引进消化吸收
        map.put("yyLlJcYj", yyLlJcYj); //应用理论基础研究
        map.put("rkxYj", rkxYj); //软科学研究
        map.put("tg", tg); //推广
        map.put("sqDwYj", isNullStr(sqDwYj)); //申请单位意见
        map.put("csYj", isNullStr(csYj)); //技术中心意见
//        map.put("mdAndYy", mdAndYy); //目的和意义

        String str = ktName + ".docx"; //课题名称.docx
        //获取yml配置地址
        String tempDir = "D:/ruoyi/uploadPath" + "/upload/";
        String name = WordUtil.easyPoiExport("static/word/proposal1.docx", tempDir, str, map, request, response);
//        String name = WordUtil.easyPoiExport("D:/ruoyi/uploadPath/upload/222.docx", tempDir, str, map, request, response);

        String finalMergeFilePath = "";

        try {
            //临时文件名称
            String mdyyFileName = "项目概述";
            //富文本内容
            String mdAndYy = llglXmsb.getMdAndYy(); //目的和意义 富文本格式
            String gnwgkAndFzqs = llglXmsb.getGnwgkAndFzqs(); //国内外概况及发展趋势 富文本格式

            //内容补充
            String firstHtmlContext = "<p><b>1、目的和意义</b></p>"
                    + mdAndYy
                    + "<p></p><p></p><p><b>2、国内外概况及发展趋势</b></p>"
                    + gnwgkAndFzqs;
            //一、项目概述
            String s = htmlStringToWord(firstHtmlContext, mdyyFileName, "一、项目概述");
            //去水印
            removeWaterMark(s, 69);

            //第一次合并
            String finalFilePath = mergeDocx(tempDir + str, s, profile + temporaryFilePath + "firstMergeDoc.docx");

            //去水印
            removeWaterMark(finalFilePath, 69);

            System.out.println("第一次合并后的路径:" + finalFilePath);
            //删除临时文件
            deleteTempFile(tempDir + str);
            deleteTempFile(s);

            //二、项目主要研究开发内容、技术关键、创新性

            //临时文件名称
            String SecondFileName = "项目研究内容";
            //富文本内容
            String zyjjKfnr = llglXmsb.getZyjjKfnr();//主要研究开发内容 富文本格式
            String gjJs = llglXmsb.getGjJs();//关键技术 富文本格式
            String cxx = llglXmsb.getCxx();//创新性 富文本格式

            //内容补充
            String secondHtmlContext = "<p><b>1、主要研究开发内容</b></p>"
                    + zyjjKfnr
                    + "<p></p><p></p><p><b>2、关键技术</b></p>"
                    + gjJs
                    + "<p></p><p></p><p><b>3、创新性</b></p>"
                    + cxx;

            //二、项目主要研究开发内容、技术关键、创新性
            String s2 = htmlStringToWord(secondHtmlContext, SecondFileName, " 二、项目主要研究开发内容、技术关键、创新性");
            //去水印
            removeWaterMark(s2, 69);

            //第二次合并
            String finalFilePath2 = mergeDocxFile(finalFilePath, s2, profile + temporaryFilePath + "secondMergeDoc.docx");
            //去水印
            removeWaterMark(finalFilePath2, 69);
            //删除临时文件
            deleteTempFile(finalFilePath);
            deleteTempFile(s2);

            // 三、技术性能指标和预期成果形式。
            //临时文件名称
            String thirdFileName = "技术性能指标";
            //富文本内容
            String yqddJsjjzb = llglXmsb.getYqddJsjjzb();//预期达到的技术经济指标 富文本格式
            String yqcgAndTgdxs = llglXmsb.getYqcgAndTgdxs();//预期成果和提供的形式 富文本格式


            //内容补充
            String thirdHtmlContext = "<p><b>1、预期达到的技术经济指标</b></p>"
                    + yqddJsjjzb
                    + "<p></p><p></p><p><b>2、预期成果和提供的形式</b></p>"
                    + yqcgAndTgdxs;

            String s3 = htmlStringToWord(thirdHtmlContext, thirdFileName, "三、技术性能指标和预期成果形式");
            //去水印
            removeWaterMark(s3, 69);
            //第三次合并
            String finalFilePath3 = mergeDocxFile(finalFilePath2, s3, profile + temporaryFilePath + "thirdMergeDoc.docx");

            removeWaterMark(finalFilePath3, 69);
            //删除临时文件
            deleteTempFile(finalFilePath2);
            deleteTempFile(s3);

            finalMergeFilePath = finalFilePath3;

        } catch (Exception e) {
            e.printStackTrace();
        }
        //前三项 doc文件 地址  finalFilePath3

        //后四项easypoi

        Map<String, Object> lastMap = new HashMap<>();
        //第四项 计划进度
        LlglXmsb jhjd = llglXmsbService.selectLlglXmsbByjhjdByXmsbId(xmsbId);
        List<LxglXmsbJhjd> JhjdList = jhjd.getLxglXmsbJhjdList();

        if (JhjdList != null) {
            IntStream.range(0, JhjdList.size())
                    .forEach(i -> {
                        LxglXmsbJhjd item = JhjdList.get(i);
                        if (item != null) {
                            item.setNumNo(i + 1);
                            String start = item.getKsRq() != null ? sdfYM.format(item.getKsRq()) : "";
                            String end = item.getJsRq() != null ? sdfYM.format(item.getJsRq()) : "";
                            item.setStartAndEndTime(start + " - " + end);
                        }
                    });
        }

        lastMap.put("JhjdList", JhjdList);

        //第五项 课题负责人(课题负责人的情况介绍)
        String ktfzrQkjs = llglXmsb.getKtfzrQkjs();

        lastMap.put("ktfzrQkjs", isNullStr(ktfzrQkjs));

        //第五项 课题承担单位的条件(课题组成人员)
        LlglXmsb getZcry = llglXmsbService.selectLlglXmsbZcryByXmsbId(xmsbId);
        List<LxglXmsbZcry> zcryList = getZcry.getLxglXmsbZcryList();
        IntStream.range(0, zcryList.size())
                .forEach(i -> {
                    LxglXmsbZcry item = zcryList.get(i);
                    item.setNumNo(i + 1);
                });
        lastMap.put("zcryList", zcryList);

        //第六项
        Double xmze = llglXmsb.getXmze();
        LlglXmsb getyffyList = llglXmsbService.selectLlglXmsbByyffyByXmsbId(xmsbId);
        List<LxglXmsbYffy> yffyList = getyffyList.getLxglXmsbYffyList();
        lastMap.put("xmze", xmze);
        lastMap.put("yffyList", yffyList);

        LlglXmsb getYffys = llglXmsbService.selectLlglXmsbByyffysByXmsbId(xmsbId);
        List<LxglXmsbYffyys> yffyysList = getYffys.getLxglXmsbYffyysList(); //研发费用预算表
        IntStream.range(0, yffyysList.size())
                .forEach(i -> {
                    LxglXmsbYffyys item = yffyysList.get(i);
                    item.setNumNo(i + 1);
                });
        lastMap.put("yffyysList", yffyysList);


        //第七项
        LlglXmsb getYfcl = llglXmsbService.selectLlglXmsbByYfclByXmsbId(xmsbId);
        List<LxglXmsbYfcl> yfclList = getYfcl.getLxglXmsbYfclList(); //直接用于研发的主要材料
        IntStream.range(0, yfclList.size())
                .forEach(i -> {
                    LxglXmsbYfcl item = yfclList.get(i);
                    item.setNumNo(i + 1);
                });
        lastMap.put("yfclList", yfclList);

        LlglXmsb getYfsb = llglXmsbService.selectLlglXmsbYfsbByXmsbId(xmsbId);
        List<LxglXmsbYfsb> yfsbList = getYfsb.getLxglXmsbYfsbList(); //设备（专门用于研发主要仪器、设备清单）
        IntStream.range(0, yfsbList.size())
                .forEach(i -> {
                    LxglXmsbYfsb item = yfsbList.get(i);
                    item.setNumNo(i + 1);
                });
        lastMap.put("yfsbList", yfsbList);

        LlglXmsb getZjsyf = llglXmsbService.selectLlglXmsbZjsyfByXmsbId(xmsbId);
        List<LxglXmsbZjsyf> zjsyfList = getZjsyf.getLxglXmsbZjsyfList(); //中间试验费
        IntStream.range(0, zjsyfList.size())
                .forEach(i -> {
                    LxglXmsbZjsyf item = zjsyfList.get(i);
                    item.setNumNo(i + 1);
                });
        lastMap.put("zjsyfList", zjsyfList);

        //导出
        String lastFileName = "last.docx"; //课题名称.docx
        //获取yml配置地址
        String suffixDir = profile + temporaryFilePath;
        String strName = WordUtil.easyPoiExport("static/word/proposal2.docx", suffixDir, lastFileName, lastMap, request, response);

        //ktName
        String lastFinalFileName = ktName + ".docx";
        //合并
        String finalPath = mergeDocxFile(finalMergeFilePath, suffixDir + lastFileName, profile + "/upload/" + lastFinalFileName);

        //去水印
        try {
            String filePath = removeWaterMark(finalPath, 69);
            //删除临时文件
            deleteTempFile(finalMergeFilePath);
            deleteTempFile(suffixDir + lastFileName);

        } catch (Exception e) {
            e.printStackTrace();
        }

        //返回最终文件名称
        return AjaxResult.success(lastFinalFileName);
    }

    /**
     * 富文本导出为docx文档
     *
     * @param htmlContext       富文本内容
     * @param temporaryFileName 导出的临时文件名称
     * @param titleName         这一块富文本的标题
     * @return
     * @throws IOException
     */
    private String htmlStringToWord(String htmlContext, String temporaryFileName, String titleName) throws IOException {
        //替换img 标签中  src的代理路径
        htmlContext = htmlContext.replace("/dev-api/profile", profile)
                .replace("/prod-api/profile", profile)
                .replace("http://localhost", "");
        //临时保存文件路径
        String filePath = profile + temporaryFilePath + temporaryFileName + ".docx";
        //新建Document对象
        com.spire.doc.Document document = new com.spire.doc.Document();
        //在此docx文件中 创一个标题样式
        ParagraphStyle style1 = new ParagraphStyle(document);
        style1.setName("titleStyle");
        style1.getCharacterFormat().setBold(true);
        style1.getCharacterFormat().setFontSize(16f);
        style1.getCharacterFormat().setFontName("Times New Roman");
        document.getStyles().add(style1);

        //添加section
        Section sec = document.addSection();

        //先新增一个标题
        Paragraph para1 = sec.addParagraph();
        //titleName 为 方法传入
        para1.appendText(titleName);
        para1.applyStyle("titleStyle");

        //img标签的 正则表达式
        String imgPattern = "<img\\s+[^>]*src=\"([^\"]*)\"[^>]*>";
        Pattern pattern = Pattern.compile(imgPattern);
        Matcher matcher = pattern.matcher(htmlContext);

        //创建表格
        Table table = sec.addTable(true);
        //只有一个单元格
        table.resetCells(1, 1);

        // 获取左页边距
        float leftMargin = sec.getPageSetup().getMargins().getLeft();
        // 获取右页边距
        float rightMargin = sec.getPageSetup().getMargins().getRight();
        double pageWidth = sec.getPageSetup().getPageSize().getWidth() - leftMargin - rightMargin;

        //获取第(1,1)单元格
        TableCell cell = table.getRows().get(0).getCells().get(0);

        int lastIndex = 0;
        while (matcher.find()) {
            // 获取 img 标签之前的 HTML 片段
            String textBeforeImg = htmlContext.substring(lastIndex, matcher.start());

            // 添加 HTML 片段到段落
            Paragraph textParagraph = cell.addParagraph();
            textParagraph.appendHTML(textBeforeImg);

            // 获取 src 属性的值
            String imgSrc = matcher.group(1);

            // 添加图片到新段落
            Paragraph imgParagraph = cell.addParagraph();
            DocPicture picture = new DocPicture(document);
            picture.loadImage(imgSrc);
            imgParagraph.getChildObjects().insert(0, picture);
            // 更新 lastIndex
            lastIndex = matcher.end();
        }
        //新增表格的段落
        Paragraph remainingTextParagraph = cell.addParagraph();
        remainingTextParagraph.appendHTML(htmlContext.substring(lastIndex));
        //表格宽度
        table.getRows().get(0).getCells().get(0).setCellWidth((float) (pageWidth * 1.3), CellWidthType.Point);
        //文档另存为docx
        document.saveToFile(filePath, FileFormat.Docx);

        return filePath;
    }

    /**
     * 合并文档  文档合并
     */
    private String mergeDocx(String filePath1, String filePath2, String finalFilePath) {

        //创建 Document 类的对象并从磁盘加载 Word 文档
        com.spire.doc.Document document = new com.spire.doc.Document(filePath1);

        //将另一个文档插入当前文档
        document.insertTextFromFile(filePath2, FileFormat.Docx);

        //保存结果文档
        document.saveToFile(finalFilePath, FileFormat.Docx);

        return finalFilePath;
    }

    /**
     * 合并文档  内容合并
     *
     * @param filePath1 最终留存文件路径
     * @param filePath2 被合并文档路径
     * @return
     */
    private String mergeDocxFile(String filePath1, String filePath2, String finalFilePath) {

        com.spire.doc.Document document1 = new com.spire.doc.Document(filePath1);
        com.spire.doc.Document document2 = new com.spire.doc.Document(filePath2);

        //在第二个文档中循环获取所有节
        for (Object sectionObj : (Iterable) document2.getSections()) {
            Section sec = (Section) sectionObj;
            //在所有节中循环获取所有子对象
            for (Object docObj : (Iterable) sec.getBody().getChildObjects()) {
                DocumentObject obj = (DocumentObject) docObj;

                //获取第一个文档的最后一节
                Section lastSection = document1.getLastSection();

                //将所有子对象添加到第一个文档的最后一节中
                Body body = lastSection.getBody();
                body.getChildObjects().add(obj.deepClone());
            }
        }

        //保存结果文档
        document1.saveToFile(finalFilePath, FileFormat.Docx);

        return finalFilePath;

    }

    /**
     * 去水印
     *
     * @param filePath 目标文件路径
     * @return
     */
    private String removeWaterMark(String filePath, int charCount) throws Exception {
        FileInputStream inputStream = new FileInputStream(filePath);
        XWPFDocument hwpfDocument = new XWPFDocument(inputStream);
        // 操作文字
        // removeText(hwpfDocument, charCount);
        // 操作段落
        removeFirstParagraph(hwpfDocument);
        OutputStream os = new FileOutputStream(filePath);

        try {
            hwpfDocument.write(os);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            os.close();
            inputStream.close();
        }
        return filePath;
    }


    private void removeText(XWPFDocument document, int charCount) {
        int removedChars = 0;
        List<XWPFParagraph> paragraphs = document.getParagraphs();

        for (XWPFParagraph paragraph : paragraphs) {
            List<XWPFRun> runs = paragraph.getRuns();
            for (XWPFRun run : runs) {
                String text = run.getText(0);
                if (text != null) {
                    int textLength = text.length();
                    if (removedChars + textLength > charCount) {
                        run.setText(text.substring(charCount - removedChars), 0);
                        return;
                    } else {
                        run.setText("", 0);
                        removedChars += textLength;
                    }
                }
            }
        }
    }

    /**
     * 溢出第一段落
     */
    private void removeFirstParagraph(XWPFDocument document) {
        List<XWPFParagraph> paragraphs = document.getParagraphs();
        if (!paragraphs.isEmpty()) {
            document.removeBodyElement(document.getPosOfParagraph(paragraphs.get(0)));
        }
    }

    /**
     * 删除临时文件
     *
     * @param filePath 目标文件地址
     */
    public void deleteTempFile(String filePath) {
        File file = new File(filePath);
        file.delete();
    }

    /**
     * 空字符串 就设置为 空格字符
     */
    private Object isNullStr(String str) {
        if (StringUtils.isEmpty(str)) {
            str = " ";
        }
        return str;
    }

    /**
     * 根据项目所属的部门ID查询它的顶级ID (非100)(分局ID)
     */
    @GetMapping(value = "/selectDjIdByXmDeptId")
    public AjaxResult selectDjIdByXmDeptId(Integer xmDeptId) {
        return success(llglXmsbService.selectDjIdByXmDeptId(xmDeptId));
    }


}
